//! Validation built-in plugin
//! 
//! This plugin provides validation and assertion functionality.

use super::BuiltinPlugin;
use crate::error::{Error, Result};
use crate::models::{Value, ValueMap};
use serde_json;
use std::collections::HashMap;

/// Validation built-in plugin
#[derive(Debug)]
pub struct ValidationPlugin {
    /// Plugin configuration
    config: ValueMap,
}

impl ValidationPlugin {
    /// Create a new validation plugin
    pub fn new() -> Self {
        Self {
            config: HashMap::new(),
        }
    }
    
    /// Validate equality
    async fn equals(&self, args: &[Value]) -> Result<Value> {
        if args.len() < 2 {
            return Err(Error::Internal("Missing values for equality check".to_string()));
        }
        
        let actual = &args[0];
        let expected = &args[1];
        let passed = actual == expected;
        
        Ok(serde_json::json!({
            "validator": "equals",
            "passed": passed,
            "actual": actual,
            "expected": expected,
            "error": if passed { serde_json::Value::Null } else { serde_json::Value::String("Values are not equal".to_string()) }
        }))
    }
    
    /// Validate contains
    async fn contains(&self, args: &[Value]) -> Result<Value> {
        if args.len() < 2 {
            return Err(Error::Internal("Missing values for contains check".to_string()));
        }
        
        let haystack = args[0].as_str().unwrap_or("");
        let needle = args[1].as_str().unwrap_or("");
        let passed = haystack.contains(needle);
        
        Ok(serde_json::json!({
            "validator": "contains",
            "passed": passed,
            "actual": haystack,
            "expected": needle,
            "error": if passed { serde_json::Value::Null } else { serde_json::Value::String("String does not contain expected value".to_string()) }
        }))
    }
    
    /// Validate status code
    async fn status_code(&self, args: &[Value]) -> Result<Value> {
        if args.len() < 2 {
            return Err(Error::Internal("Missing status codes for comparison".to_string()));
        }
        
        let actual = args[0].as_u64().unwrap_or(0) as u16;
        let expected = args[1].as_u64().unwrap_or(0) as u16;
        let passed = actual == expected;
        
        Ok(serde_json::json!({
            "validator": "status_code",
            "passed": passed,
            "actual": actual,
            "expected": expected,
            "error": if passed { serde_json::Value::Null } else { serde_json::Value::String(format!("Status code mismatch: expected {}, got {}", expected, actual)) }
        }))
    }
    
    /// Validate JSON path
    async fn jsonpath(&self, args: &[Value]) -> Result<Value> {
        if args.len() < 3 {
            return Err(Error::Internal("Missing JSON data, path, or expected value".to_string()));
        }
        
        let json_data = &args[0];
        let path = args[1].as_str().unwrap_or("");
        let expected = &args[2];
        
        // TODO: Implement actual JSONPath validation
        // This is a placeholder implementation
        let passed = true; // Placeholder
        
        Ok(serde_json::json!({
            "validator": "jsonpath",
            "passed": passed,
            "path": path,
            "actual": json_data,
            "expected": expected,
            "error": if passed { serde_json::Value::Null } else { serde_json::Value::String("JSONPath validation failed".to_string()) }
        }))
    }
    
    /// Validate regular expression
    async fn regex(&self, args: &[Value]) -> Result<Value> {
        if args.len() < 2 {
            return Err(Error::Internal("Missing text or pattern".to_string()));
        }
        
        let text = args[0].as_str().unwrap_or("");
        let pattern = args[1].as_str().unwrap_or("");
        
        match regex::Regex::new(pattern) {
            Ok(re) => {
                let passed = re.is_match(text);
                Ok(serde_json::json!({
                    "validator": "regex",
                    "passed": passed,
                    "actual": text,
                    "pattern": pattern,
                    "error": if passed { serde_json::Value::Null } else { serde_json::Value::String("Text does not match regex pattern".to_string()) }
                }))
            }
            Err(e) => Ok(serde_json::json!({
                "validator": "regex",
                "passed": false,
                "actual": text,
                "pattern": pattern,
                "error": format!("Invalid regex pattern: {}", e)
            })),
        }
    }
    
    /// Validate response time
    async fn response_time(&self, args: &[Value]) -> Result<Value> {
        if args.len() < 2 {
            return Err(Error::Internal("Missing response time values".to_string()));
        }
        
        let actual_ms = args[0].as_f64().unwrap_or(0.0);
        let max_ms = args[1].as_f64().unwrap_or(0.0);
        let passed = actual_ms <= max_ms;
        
        Ok(serde_json::json!({
            "validator": "response_time",
            "passed": passed,
            "actual": actual_ms,
            "max_allowed": max_ms,
            "error": if passed { serde_json::Value::Null } else { serde_json::Value::String(format!("Response time {}ms exceeds maximum {}ms", actual_ms, max_ms)) }
        }))
    }
    
    /// Validate header
    async fn header(&self, args: &[Value]) -> Result<Value> {
        if args.len() < 3 {
            return Err(Error::Internal("Missing headers, header name, or expected value".to_string()));
        }
        
        let headers = &args[0];
        let header_name = args[1].as_str().unwrap_or("");
        let expected = args[2].as_str().unwrap_or("");
        
        let actual = headers.get(header_name)
            .and_then(|v| v.as_str())
            .unwrap_or("");
        
        let passed = actual == expected;
        
        Ok(serde_json::json!({
            "validator": "header",
            "passed": passed,
            "header": header_name,
            "actual": actual,
            "expected": expected,
            "error": if passed { serde_json::Value::Null } else { serde_json::Value::String(format!("Header '{}' mismatch: expected '{}', got '{}'", header_name, expected, actual)) }
        }))
    }
    
    /// Validate type
    async fn type_check(&self, args: &[Value]) -> Result<Value> {
        if args.len() < 2 {
            return Err(Error::Internal("Missing value or expected type".to_string()));
        }
        
        let value = &args[0];
        let expected_type = args[1].as_str().unwrap_or("");
        
        let actual_type = match value {
            Value::Null => "null",
            Value::Bool(_) => "boolean",
            Value::Number(_) => "number",
            Value::String(_) => "string",
            Value::Array(_) => "array",
            Value::Object(_) => "object",
        };
        
        let passed = actual_type == expected_type;
        
        Ok(serde_json::json!({
            "validator": "type",
            "passed": passed,
            "actual_type": actual_type,
            "expected_type": expected_type,
            "error": if passed { serde_json::Value::Null } else { serde_json::Value::String(format!("Type mismatch: expected {}, got {}", expected_type, actual_type)) }
        }))
    }
}

impl BuiltinPlugin for ValidationPlugin {
    fn name(&self) -> &str {
        "validation"
    }
    
    fn version(&self) -> &str {
        "1.0.0"
    }
    
    fn functions(&self) -> Vec<String> {
        vec![
            "equals".to_string(),
            "contains".to_string(),
            "status_code".to_string(),
            "jsonpath".to_string(),
            "regex".to_string(),
            "response_time".to_string(),
            "header".to_string(),
            "type".to_string(),
        ]
    }
    
    async fn call_function(&self, function_name: &str, args: &[Value]) -> Result<Value> {
        match function_name {
            "equals" => self.equals(args).await,
            "contains" => self.contains(args).await,
            "status_code" => self.status_code(args).await,
            "jsonpath" => self.jsonpath(args).await,
            "regex" => self.regex(args).await,
            "response_time" => self.response_time(args).await,
            "header" => self.header(args).await,
            "type" => self.type_check(args).await,
            _ => Err(Error::Plugin(crate::error::PluginError::FunctionNotFound {
                function_name: function_name.to_string(),
            })),
        }
    }
    
    async fn initialize(&mut self, config: ValueMap) -> Result<()> {
        self.config = config;
        tracing::info!("Validation plugin initialized");
        Ok(())
    }
    
    async fn cleanup(&mut self) -> Result<()> {
        tracing::info!("Validation plugin cleaned up");
        Ok(())
    }
}

impl Default for ValidationPlugin {
    fn default() -> Self {
        Self::new()
    }
}
